import json
from flask_sqlalchemy import SQLAlchemy
from packages.core.db.decorators import Transactional
from modules.sys.enums.menu_app_code_enum import MenuAppCodeEnum
from packages.core.auth.login_user_holder import LoginUserHolder
from modules.sys.models.menu import Menu
from modules.sys.models.role_menu import RoleMenu
from packages.tools.base_tool import build_tree, generate_id
from packages.tools.db_tool import DbTool
from sqlalchemy import asc
from modules.sys.services.rbac_service import RbacService
from packages.common.base import IdForm, IdsForm
from modules.sys.validators.menu_validator import MenuForm, MenuPageForm


class MenuService():
    """
    菜单模块业务处理类
    """
    def __init__(self, db: SQLAlchemy):
        self.model = Menu
        self.db = db
        self.rbac_service = RbacService(db=db)

    def detail(self, form: IdForm):
        """
        通过id获取信息
        :param form:
        :return:
        """
        model = self.db.session.query(self.model).get(form.id.data)
        return model

    def page(self, form: MenuPageForm):
        """
        分页查询列表
        :param form:
        :return:
        """
        # 可通过form.data获取所有提交参数
        # 可通过form.pageNum.data获取pageNum
        # 可通过form.pageSize.data获取pageSize
        # page=self.db.query(User).filter().paginate(form.pageNum.data, form.pageSize.data,False)
        pageNum = form.data.get("pageNum", 1)
        pageSize = form.data.get("pageSize", 10)
        page = DbTool.filter_by_custom(self.model).paginate(page=pageNum, per_page=pageSize, error_out=False)
        return self.model.to_page(page)

    @Transactional()
    def save(self, form: MenuForm):
        """
        添加
        :param form:
        :return:
        """
        model = self.model(**form.data)
        model.id = generate_id()
        model.createUser = LoginUserHolder.get_user_id()
        model.updateUser = LoginUserHolder.get_user_id()

        self.db.session.add(model)

    @Transactional()
    def update(self, form: MenuForm):
        """
        修改
        :param form:
        :return:
        """
        model = self.model(**form.data)

        model.updateUser = LoginUserHolder.get_user_id()

        self.db.session.query(self.model).filter_by(id=form.id.data).update(
            model.to_dict()
        )

    @Transactional()
    def remove(self, form: IdsForm):
        """
        删除
        :param form:
        :return:
        """
        self.model().remove(self.model, form.ids.data)

    def app_list(self):
        """
        应用列表
        """
        res = []
        for member in MenuAppCodeEnum:
            res.append({"label": member.msg, "value": member.name.lower()})
        return res

    def list(self):
        """
        菜单列表
        """
        list = DbTool.filter_by_custom(Menu).order_by(asc(Menu.sort)).all()
        return Menu.to_dict_list(list)

    def tree(self):
        """
        菜单树
        """
        list = DbTool.filter_by_custom(Menu).order_by(asc(Menu.sort)).all()
        return build_tree(Menu.to_dict_list(list))

    @Transactional()
    def sync_route(self, routeList):
        """
        同步路由
        """
        menuIds = []
        if routeList is not None and len(routeList) > 0:
            # 一级菜单
            for route in routeList:
                isSync = route.get("isSync")
                if isSync == 1:
                    menuId = self.save_or_update_route(route, 0)
                    menuIds.append(menuId)
                    # 二级菜单
                    if (
                        route.get("children") is not None
                        and len(route.get("children")) > 0
                    ):
                        for child in route.get("children"):
                            menuId2 = self.save_or_update_route(child, menuId)
                            menuIds.append(menuId2)
                            # 三级菜单
                            if (
                                child.get("children") is not None
                                and len(child.get("children")) > 0
                            ):
                                for grandson in child.get("children"):
                                    menuId3 = self.save_or_update_route(
                                        grandson, menuId2
                                    )
                                    menuIds.append(menuId3)
                                    # 四级菜单
                                    if (
                                        grandson.get("children") is not None
                                        and len(grandson.get("children")) > 0
                                    ):
                                        for greatGrandson in grandson.get("children"):
                                            menuId4 = self.save_or_update_route(
                                                greatGrandson, menuId3
                                            )
                                            menuIds.append(menuId4)
        # 删除前端同步菜单、当前应用、不在当前同步菜单内的路由菜单
        appCode = LoginUserHolder.get_app_code()
        if len(menuIds) == 0:
            menuIds.append(0)
        self.db.session.query(Menu).filter(
            Menu.appCode == appCode, Menu.isSync == 1, Menu.id.notin_(menuIds)
        ).delete()

        sysMenus = (
            self.db.session.query(Menu)
            .filter(Menu.appCode == appCode, Menu.isSync == 1, Menu.id.notin_(menuIds))
            .all()
        )
        if len(sysMenus) > 0:
            deleteMenuIds = [menu.id for menu in sysMenus]
            # 删除冗余菜单
            self.db.session.query(Menu).filter(Menu.id.in_(deleteMenuIds)).delete()
            # 清除角色菜单关联表
            self.db.session.query(RoleMenu).filter(
                RoleMenu.menuId.in_(deleteMenuIds)
            ).delete()

    def save_or_update_route(self, route, pid):
        """
        保存或更新路由
        """
        menu = Menu(**route)
        menu.code = route.get("code")
        menu.appCode = LoginUserHolder.get_app_code()
        menu.parentId = pid
        menu.pids = ""
        if menu.openType is None:
            menu.openType = 0
        newPids = self.create_new_pids(pid)
        menu.pids = newPids
        menu.variable = "{}"
        oldMenu = self.get_menu(menu.code, pid)
        if oldMenu is not None:
            # 存在则更新
            menu.updateUser = LoginUserHolder.get_user_id()
            self.db.session.query(Menu).filter_by(id=oldMenu.id).update(menu.to_dict())
            return oldMenu.id
        else:
            menu.createUser = LoginUserHolder.get_user_id()
            menu.updateUser = LoginUserHolder.get_user_id()
            menu.id = generate_id()
            self.db.session.add(menu)
            return menu.id

    def create_new_pids(self, pid):
        if pid == 0:
            return "[" + str(pid) + "]" + ","
        else:
            # 获取父菜单
            parentMenu = self.db.session.query(Menu).filter_by(id=pid).first()
            if parentMenu is not None:
                print("pids:" + parentMenu.pids)
                return parentMenu.pids + "[" + str(pid) + "]" + ","

    def get_menu(self, code, pid):
        """
        根据code获取菜单
        """
        appCode = LoginUserHolder.get_app_code()
        return (
            self.db.session.query(Menu)
            .filter_by(code=code, parentId=pid, appCode=appCode)
            .first()
        )

    def user_route_menu(self, version: str = "v5"):
        """
        获取用户路由菜单（支持多版本格式）
        """
        # 查询启用的菜单
        menu_list = (
            Menu.query.filter_by(enabled=1, appCode=LoginUserHolder.get_app_code())
            .filter(Menu.type.in_([1, 2]))  # 1:目录 2:菜单
            .order_by(asc(Menu.sort))
            .all()
        )
        # 获取用户权限（非超级管理员需要过滤）
        current_user = LoginUserHolder.get()
        user_id = current_user.get("id")
        if not current_user.get("superAdmin", False):
            user_menu_ids = self.rbac_service.get_menu_ids_by_user_id(user_id)
            menu_list = [menu for menu in menu_list if menu.id in user_menu_ids]
        # 处理art-design-pro专用权限数据
        perm_code_list = []
        if version == "art-design-pro":
            perm_code_list = [
                {"authMark": perm_code, "title": perm_code}
                for perm_code in current_user.get("perms", [])
            ]

        def format_menu(menu):
            """格式化单个菜单项"""
            meta = {
                "title": menu.name,
                "order": menu.sort,
                **(json.loads(menu.variable) if menu.variable else {}),
            }
            # 处理图标和链接类型
            if menu.icon:
                meta["icon"] = menu.icon
            if menu.openType == 3:  # 内部链接
                meta["link"] = menu.url
            elif menu.openType == 4:  # 外部链接
                meta["iframeSrc"] = menu.url
            # 隐藏菜单处理
            if menu.isShow != 1:
                meta["hideInMenu" if version != "v2" else "hideMenu"] = True
            # 缓存配置
            if menu.isCache == 1:
                meta["keepAlive"] = True
            # art-design-pro专用处理
            if version == "art-design-pro":
                meta.pop("link", None)
                meta.pop("iframeSrc", None)
                # 处理链接类型
                if menu.openType == 3:
                    meta["link"] = menu.url
                    meta["isIframe"] = False
                elif menu.openType == 4:
                    meta["link"] = menu.url
                    meta["isIframe"] = True
                # 添加权限列表
                meta["authList"] = perm_code_list
            return {
                "id": menu.id,
                "parentId": menu.parentId or "0",
                "name": menu.code,
                "component": menu.component,
                "path": menu.path,
                "redirect": None,
                "meta": meta
            }

        # 格式化所有菜单并构建树形结构
        route_menu_list = [format_menu(menu) for menu in menu_list]
        return build_tree(route_menu_list)
